package com.data.capture.config.properties;

import com.data.capture.constant.OperationType;
import com.data.capture.mq.dto.ChangeDataCaptureInfo;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import lombok.extern.log4j.Log4j2;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * 数据捕获参数配置
 * @author zhangbh
 */
@Data
@Log4j2
@Accessors(chain = true)
@NoArgsConstructor
public class CdcProperties implements Serializable {

    /**
     * MQ主题名称
     */
    private String topicName;
    /**
     * 监控数据表列表
     */
    private String tableList;
    /**
     * 监控变化的字段（如果为空则不限制）
     */
    private Set<String> includeFieldList;
    /**
     * 排除监控变化的字段（如果为空则不限制）
     */
    private Set<String> excludeFieldList;
    /**
     * 是否只推送id
     */
    private Boolean onlyPushPrimary = false;
    private String includeField;
    private String excludeField;

    public CdcProperties(CdcProperties properties, List<String> tableNameList) {
        tableList = String.join(",", tableNameList);
        topicName = properties.getTopicName();
        includeFieldList = properties.getIncludeFieldList();
        excludeFieldList = properties.getExcludeFieldList();
        includeField = properties.getIncludeField();
        excludeField = properties.getExcludeField();
        onlyPushPrimary = properties.getOnlyPushPrimary();
    }

    public boolean needPush(ChangeDataCaptureInfo info) {
        if (!OperationType.UPDATE.eq(info.getType())) {
            return true;
        }
        // 1. 如果IncludeFieldList不为空，变化的字段全部都不在IncludeFieldList范围则不推送
        if (!includeFieldList.isEmpty()) {
            for (String changeField : info.getChangeFields()) {
                if (includeFieldList.contains(changeField)) {
                    return true;
                }
            }
            return false;
        }
        // 2. 如果ExcludeFieldList不为空，变化的字段全部都再ExcludeFieldList范围则不推送
        // 包含正则匹配，如JZW.*也算
        if (!excludeFieldList.isEmpty()) {
            List<String> changeFields = excludeReg(info.getChangeFields());
            return !excludeFieldList.containsAll(changeFields);
        }
        return true;
    }

    private List<String> excludeReg(List<String> changeFields) {
        // 排除掉正则忽略的字段
        List<String> result = new ArrayList<>(changeFields);
        for (String excludeField : excludeFieldList) {
            if (excludeField.contains(".*")) {
                result.removeIf(changeField -> {
                    boolean matches = changeField.matches(excludeField);
                    if (matches) {
                        log.debug("【数据变更信息流】正则匹配到排除字段 excludeField={} changeField={}", excludeField, changeField);
                    }
                    return matches;
                });
            }
        }
        return result;
    }
}
